/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package com.azon.left.hand;

import java.awt.Point;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;

/**
 *
 * @author Mahdan Ahmad F A
 */
public class ThinnedWetLeftHand extends WetLeftHand {

    @Override
    public String[] doWetLeftHand(int[][] matrix) {
        
        ArrayList<String> array = new ArrayList<>();
        
        int[] start = getDeadEnd(matrix);
        
        int iteration = 0;
        
        while (((start[0] != -28) && (start[1] != -28))/* && (iteration < 10)*/) {
            String chain_code = createAChainCode(matrix, start[0], start[1]);
            if (chain_code.length() < 20) {
                
            } else {
                array.add(chain_code);
                iteration++;
            }
            
            start = getDeadEnd(matrix);
            //System.out.println(array.get(iteration));

            //System.out.println(start[0] + " " + start[1]);
            
            
            
        }
        
        String[] chain_codes = array.toArray(new String[array.size()]);
        return chain_codes;
    }
    
    private String createAChainCode(int[][] matrix, int startX, int startY) {
        
        String chain_code = "";

        Integer[] nextCounter = countNext(matrix, startX, startY);
        int posX = startX;
        int posY = startY;
        matrix[posX][posY] = 1;
        int[] next = null;
        
        boolean queue_flag = false;
        
        Queue<Point> queue       = new LinkedList<>();
        Queue<Point> queue_cross = new LinkedList<>();
        
        while(nextCounter[0] != 0) {
            
            if (nextCounter[0] == 1) {
                chain_code += nextCounter[1];
                
                next = getNext(posX, posY, nextCounter[1]);
            } else if (nextCounter[0] == 2) {
                //System.out.println(posX + " " + posY);
                //chain_code += "*";
                if(!queue_flag) {
                    queue_flag = true;
                    queue.add(new Point(posX, posY));
                }
                
                boolean flag = false;                    
                Integer last = 6;
                
                if (chain_code.isEmpty()) {
                    
                } else {
                    last = chain_code.charAt(chain_code.length() - 1) - 48;
                }
                
                for (int i = 1; i < nextCounter.length; i++) {
                    if (last == nextCounter[i]) {
                        flag = true;
                    }
                }
                
                if (flag) {
                    chain_code += last;
                    
                    next = getNext(posX, posY, last);
                } else {
                    chain_code += nextCounter[nextCounter[0]];
                    
                    next = getNext(posX, posY, nextCounter[nextCounter[0]]);

                }
            } else if (nextCounter[0] == 3) {
                boolean flag = false;                    
                Integer last = 6;
                
                if (chain_code.isEmpty()) {
                    
                } else {
                    last = chain_code.charAt(chain_code.length() - 1) - 48;
                }
                
                for (int i = 1; i < nextCounter.length; i++) {
                    if (last == nextCounter[i]) {
                        flag = true;
                    }
                }
                
                if (flag) {
                    chain_code += last;
                    queue_cross.add(new Point(posX, posY));
                    next = getNext(posX, posY, last);
                }
            } else {
                System.out.println("Ada lebih banyak persimpangan " + nextCounter[0]);
                break;
            }

            posX = next[0];
            posY = next[1];
            
            if (queue_flag) {
                queue.add(new Point(posX, posY));
            }
            
            matrix[posX][posY] = 1;
            nextCounter = countNext(matrix, posX, posY);
            
            if (nextCounter[0] == 0) {
                
                if(!queue_cross.isEmpty()) {

                    Point pos = queue_cross.remove();
                    matrix[pos.x][pos.y] = 0;
                    nextCounter = countNext(matrix, posX, posY);

                } // */
                
                if (queue_flag) {
                    Point pos = queue.remove();
                    
                    if (isConnected(pos, new Point(posX, posY))) {
                        //System.out.println("Udah balik lagi");
                        break;
                    } else {
                        if(!isConnected(new Point(posX, posY), new Point(startX, startY))) {
                            matrix[pos.x][pos.y] = 0;

                            while(!queue.isEmpty()) {
                                pos = queue.remove();
                                matrix[pos.x][pos.y] = 0;

                            }

                            matrix[posX][posY] = 1;
                            nextCounter = countNext(matrix, posX, posY);
                            queue_flag = false;
                        }
                        
                    }
                    
                } else {
                    //System.out.println("Flag ga nyala");
                    
                }
            }
        }
        
        return startX + "X" + startY + "Y" + chain_code;
    }
    
    private int[] getDeadEnd(int[][] matrix) {
        
        int[] start = new int[2];
        
        int[] actualStart = detectorBlack(matrix);
        
        if ((actualStart[0] != -28) && actualStart[1] != -28) {
            boolean[][] flag_matrix = new boolean[matrix.length][matrix[0].length];

            for (int m = 0; m < matrix.length; m++) {
                for (int n = 0; n < matrix[0].length; n++) {
                    flag_matrix[m][n] = matrix[m][n] == 0;
                }
            }

            Queue<Point> queue = new LinkedList<>();
            queue.add(new Point(actualStart[0], actualStart[1]));

            flag_matrix[actualStart[0]][actualStart[1]] = false;

            while (!queue.isEmpty()) {
                Point pos = queue.remove();

                //System.out.println("NOW!!" + pos.toString());

                if (countNext(matrix, pos.x, pos.y)[0] < 2) {
                    start[0] = pos.x;
                    start[1] = pos.y;
                    break;
                } else {
                    String direction = "12346789";

                    for (int i = 0; i < direction.length(); i++) {
                        if (isAvailable(matrix, pos.x, pos.y, (direction.charAt(i) - 48))) {
                            int next[] = getNext(pos.x, pos.y, (direction.charAt(i) - 48));

                            if (flag_matrix[next[0]][next[1]]) {
                                flag_matrix[next[0]][next[1]] = false;
                                queue.add(new Point(next[0], next[1]));
                            }
                        }
                    }
                }
            }
        }
        if ((start[0] == 0) && start[1] == 0) {
            start[0] = actualStart[0];
            start[1] = actualStart[1];
        }

            //System.out.println(actualStart[0] + " " + actualStart[1]);
            //System.out.println(start[0] + " " + start[1]);

        return start;
    }
    
    private Integer[] countNext(int[][] matrix, int posX, int posY) {
        int next = 0;
           
        ArrayList<Integer> array = new ArrayList<>();
        array.add(0);
        
        String direction = "12346789";
        
        for (int i = 0; i < direction.length(); i++) {
            if (isAvailable(matrix, posX, posY, (direction.charAt(i) - 48))) {
                next++;
                array.set(0, next);
                array.add((direction.charAt(i) - 48));
            }
            
            //System.out.println(isAvailable(matrix, posX, posY, (direction.charAt(i) - 48)));
        }
        
        Integer[] result = array.toArray(new Integer[array.size()]);
        
        return result;
    }

    private boolean isAvailable(int[][] matrix, int startX, int startY, int direction ) {
        
        int[] position = getNext(startX, startY, direction);
        
        int posX = position[0];
        int posY = position[1];
                
        int maxX = matrix.length - 1;
        int maxY = matrix[0].length - 1;
        
        switch(direction) {
            case 1:
                //System.out.print("Nilai matrik di posisi " + direction + "(" + posX + "," + posY + ")" + " = " + matrix[posX][posY]);
                if (startX == 0) {
                    return false;
                } else {
                    if ((matrix[posX][posY] == 0) && (matrix[posX][posY+1] == 1) && (matrix[posX+1][posY] == 1)) {
                        return true;
                    }
                }
                break;
            case 2:
                //System.out.print("Nilai matrik di posisi " + direction + "(" + posX + "," + posY + ")" + " = " + matrix[posX][posY]);
                if (startX == 0) {
                    if (startY == 0) {
                        return false;
                    } else if (matrix[posX][posY] == 0) {
                        return true;
                    }
                } else {
                    if ((matrix[posX][posY] == 0)) {
                        return true;
                    }
                }
                break;
            case 3:
                //System.out.print("Nilai matrik di posisi " + direction + "(" + posX + "," + posY + ")" + " = " + matrix[posX][posY]);
                if (startY == 0) {
                    return false;
                } else {
                    if ((matrix[posX][posY] == 0)&& (matrix[posX][posY-1] == 1) && (matrix[posX+1][posY] == 1)) {
                        return true;
                    }
                }
                break;
            case 4:
                //System.out.print("Nilai matrik di posisi " + direction + "(" + posX + "," + posY + ")" + " = " + matrix[posX][posY]);
                if (startY == maxY) {
                    if (startX == 0) {
                        return false;
                    } else if (matrix[posX][posY] == 1) {
                        return true;
                    }
                } else {
                    if ((matrix[posX][posY] == 0)) {
                        return true;
                    }
                }
                break;
            case 6:
                //System.out.print("Nilai matrik di posisi " + direction + "(" + posX + "," + posY + ")" + " = " + matrix[posX][posY]);
                if (startY == 0) {
                    if (startX == maxX) {
                        return false;
                    } else if (matrix[posX][posY] == 1) {
                        return true;
                    }
                } else {
                    if ((matrix[posX][posY] == 0)) {
                        return true;
                    }
                }
                break;
            case 7:
                //System.out.print("Nilai matrik di posisi " + direction + "(" + posX + "," + posY + ")" + " = " + matrix[posX][posY]);
                if (startX == maxX) {
                    return false;
                } else {
                    if ((matrix[posX][posY] == 0)&& (matrix[posX-1][posY] == 1) && (matrix[posX][posY+1] == 1)) {
                        return true;
                    }
                }
                break;
            case 8:
                //System.out.print("Nilai matrik di posisi " + direction + "(" + posX + "," + posY + ")" + " = " + matrix[posX][posY]);
                if (startX == maxX) {
                    if (startY == maxY) {
                        return false;
                    } else if (matrix[posX][posY] == 1) {
                        return true;
                    }
                } else {
                    if ((matrix[posX][posY] == 0)) {
                        return true;
                    }
                }
                break;
            case 9:
                //System.out.print("Nilai matrik di posisi " + direction + "(" + posX + "," + posY + ")" + " = " + matrix[posX][posY]);
                if (startY == maxY) {
                    return false;
                } else {
                    if ((matrix[posX][posY] == 0)&& (matrix[posX-1][posY] == 1) && (matrix[posX][posY-1] == 1)) {
                        return true;
                    }
                }
                break;
        }
        
        return false;
    }
    
    private boolean isConnected(Point a, Point b) {
        
        double distance = a.distance(b);
        
        return (distance < 1.8);
    }

}
